﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Data;
using System.Linq;

namespace TCP.SocketHelper
{
    /// <summary>
    /// Socket的服务端，运行于服务器上，服务端的主程序
    /// </summary>
    public class SocketServer<T> : BaseTCPSocket where T : SocketClient, new()
    {
        /// <summary>
        /// 最大客户端连接数
        /// </summary>
        protected int _ClientMax = 10;

        /// <summary>
        /// 当前连入的活跃客户端
        /// </summary>
        protected List<T> _Clients = new List<T>();

        /// <summary>
        /// 记录各客户端和客户端的识别身份
        /// </summary>
        protected Dictionary<string, T> _ClientsDict = new Dictionary<string, T>();

        #region --Public Callback Event

        /// <summary>
        /// 连接成功的回调（参数为客户端Socket）
        /// </summary>
        public Action<T> OnClientConnectSuccessAction = null;

        /// <summary>
        /// 连接失败的回调(参数为服务器Socket自身)
        /// </summary>
        public Action<Socket> OnClientConnectFailAction = null;

        /// <summary>
        /// 接收到客户端消息时的回调
        /// </summary>
        public Action<byte[]> OnClientMsgReceiveAction = null;

        /// <summary>
        /// 当服务端断连时的回调
        /// </summary>
        public Action<T> OnClientDropAction = null;

        /// <summary>
        /// 客户端日志回调
        /// </summary>
        public Action<object, int> OnClientLogAction = null;

        #endregion

        #region --Public Property

        /// <summary>
        /// 客户端列表
        /// </summary>
        public List<T> Client
        {
            get
            {
                return _Clients;
            }
        }

        /// <summary>
        /// 客户端列表(名称)
        /// </summary>
        public Dictionary<string, T> ClientDict
        {
            get
            {
                return _ClientsDict;
            }
        }

        /// <summary>
        /// 获取一个客户端
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T this[int index]
        {
            get
            {
                if (_Clients == null || _Clients.Count <= 0)
                {
                    Log($"{GetType()}._Clients is null.");
                    return null;
                }

                if (index < 0 || index >= _Clients.Count)
                {
                    Log($"{GetType()}._Clients don't have index={index}");
                    return null;
                }

                return _Clients[index];
            }
        }

        /// <summary>
        /// 获取一个客户端(需要先确认名字)
        /// </summary>
        /// <param name="clientName"></param>
        /// <returns></returns>
        public T this[string clientName]
        {
            get
            {
                if (_ClientsDict == null || _ClientsDict.Count <= 0)
                {
                    Log($"{GetType()}._ClientsDict is null.");
                    return null;
                }

                if (!_ClientsDict.ContainsKey(clientName))
                {
                    Log($"{GetType()}._ClientsDict don't have name={clientName}");
                    return null;
                }

                return _ClientsDict[clientName];
            }
        }

        #endregion --Public Property

        #region --Public Methods

        /// <summary>
        /// 构造一个监听服务
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="clientMax"></param>
        public SocketServer(string ip, int port, int clientMax = 10)
        {
            _TargetIP = ip;
            _TargetPort = port;
            _ClientMax = clientMax;
        }

        /// <summary>
        /// 开启服务端的连接（绑定）
        /// </summary>
        public override void StartConnect()
        {

            try
            {
                if (_TargetIP == SocketSetting.AUTO_SYMBOL_IP)
                {
                    _TargetIP = GetLocalIp();
                }

                IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(_TargetIP), _TargetPort);
                IPAddress[] hostAddresses = Dns.GetHostAddresses(_TargetIP);
                if (hostAddresses[0].AddressFamily == AddressFamily.InterNetworkV6)
                {
                    _Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
                }
                else
                {
                    _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                }

                _Socket.Bind(endPoint);
                _Socket.Listen(_ClientMax);
                _IsConnect = true;
            }
            catch (Exception ex)
            {
                Log($"{GetType()}.StartConnect:{ex.Message}", 1);
            }

            Log($"{GetType()}.StartConnect:Server run on {_TargetIP}:{_TargetPort}");
            IAsyncResult asyncResult = _Socket.BeginAccept(new AsyncCallback(OnAccept), _Socket);
        }

        /// <summary>
        /// 广播到所有客户端
        /// </summary>
        /// <param name="data"></param>
        public virtual void Broadcast(byte[] data)
        {
            lock (_Clients)
            {
                foreach (T client in _Clients)
                {
                    client.SendMessage(data);
                }
            }
        }

        /// <summary>
        /// 获取本机IP
        /// <para>只适用于IPv4</para>
        /// </summary>
        /// <returns></returns>
        public virtual string GetLocalIp()
        {
            string AddressIP = SocketSetting.DEFAULT_IPADDRESS_V4;
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily == AddressFamily.InterNetwork)
                {
                    AddressIP = _IPAddress.ToString();
                }
            }
            return AddressIP;
        }

        #endregion Public Methods


        #region Protect Methods
        /// <summary>
        /// 接收到客户端连入的异步结果
        /// </summary>
        /// <param name="result"></param>
        protected virtual void OnAccept(IAsyncResult result)
        {
            if ((Socket)result.AsyncState == null)
            {
                NetDrop($"{GetType()}.OnAccept:AsyncState is null.");
                return;
            }
            Socket client = _Socket.EndAccept(result);
            Log("OnAccept:" + client.RemoteEndPoint);
            _Socket.BeginAccept(new AsyncCallback(OnAccept), _Socket);

            T clientcon = new T();
            clientcon.SetSocketClient(client);
            _Clients.Add(clientcon);

            if (OnClientMsgReceiveAction != null)
            {
                Log($"{client.RemoteEndPoint} add {GetType()}.OnClientMsgReceiveAction");
                clientcon.ReceiveMsgAction += OnClientMsgReceiveAction;
            }

            if (OnClientLogAction != null)
            {
                Log($"{client.RemoteEndPoint} add {GetType()}.LogAction");
                clientcon.LogAction += OnClientLogAction;
            }

            if (OnClientDropAction != null)
            {
                Log($"{client.RemoteEndPoint} add {GetType()}.OnClientDropAction");
                clientcon.OnNetDropAction += (Action<BaseTCPSocket>)OnClientDropAction;
            }

            if (OnClientConnectSuccessAction != null)
            {
                OnClientConnectSuccessAction(clientcon);
            }

            clientcon.OnConrimNameAction += OnClientConfirmName;
            clientcon.OnNetDropAction += OnClientDrop;
        }

        /// <summary>
        /// 在客户端确认名字时
        /// </summary>
        /// <param name="name"></param>
        /// <param name="sender"></param>
        protected virtual void OnClientConfirmName(string name, SocketClient sender)
        {
            if (_ClientsDict.ContainsKey("name"))
            {
                Log($"{GetType()}._ClientsDict has {name} already,can not add in", 2);
                return;
            }

            Log($"{GetType()}._ClientsDict add {name}", 0);
            _ClientsDict.Add(name, (T)sender);
        }

        /// <summary>
        /// 在客户端断开时
        /// </summary>
        protected virtual void OnClientDrop(BaseTCPSocket client)
        {
            T Tclient = client as T;
            if (Tclient == null)
            {
                Log($"{GetType()}.OnClientDrop client({client.RemoteIP}) cast to {typeof(T)} fail.", 1);
                return;
            }

            Log($"{GetType()}.OnClientDrop client({client.RemoteIP}) disconnect", 0);

            string key = string.Empty;
            foreach (KeyValuePair<string, T> pair in _ClientsDict)
            {
                if(pair.Value == Tclient)
                {
                    key = pair.Key;
                    break;
                }
            }

            if(!string.IsNullOrEmpty(key))
            {
                _ClientsDict.Remove(key);
            }

            if(_Clients.Contains(Tclient))
            {
                _Clients.Remove(Tclient);
            }
        }

        #endregion Protect Methods
    }
}
